import axios from "axios";
import config from "@/config";
import tool from "@/utils/tool.js";
import router from "../router";
import { ElMessageBox, ElMessage } from "element-plus";

// 接口超时设置
axios.defaults.timeout = config.TIMEOUT;

// 接口白名单
const requestWhiteList = [
  "/api/auth/v1.0/login",
  "api/auth/v1.0/login",
  "api/auth/v1.0/token",
  "api/auth/v1.0/token/refresh",
];

// 是否正在刷新token
let isRefreshing = false;
// 重试队列
let retryQueue = [];

// 多接口鉴权保证只弹出一个弹窗
let modal_error_401 = false;

// 校验url
const checkUrl = (url) => {
  return !requestWhiteList.some((item) => {
    return url.includes(item);
  });
};

// 添加请求拦截器
axios.interceptors.request.use(
  (request) => {
    // 设置Token登录信息
    let token = JSON.parse(tool.session.get("token"))
      ? JSON.parse(tool.session.get("token"))
      : "";
    let userCode = JSON.parse(tool.session.get("userInfo"))?.userCode;
    if (token && userCode) {
      // token信息和用户信息都存在
      request.headers["AUTH-TOKEN"] = token;
      request.headers["USER-CODE"] = userCode;
    } else if (checkUrl(request.url)) {
      // token信息或用户信息不存在、非白名单
      if (!modal_error_401) {
        modal_error_401 = true;
        // 弹出提示框
        ElMessageBox.confirm(
          "当前用户已被登出或无权限访问当前资源，请尝试重新登录后再操作。",
          "无权限访问",
          {
            confirmButtonText: "重新登录",
            cancelButtonText: "取消",
            type: "warning",
          }
        )
          .then(() => {
            modal_error_401 = false;
            router.replace({ path: "/" });
          })
          .catch(() => {
            modal_error_401 = false;
          });
        return Promise.reject();
      }
    }
    return request;
  },
  (error) => {
    return Promise.reject(error);
  }
);

// 添加响应拦截器
axios.interceptors.response.use(
  (response) => {
    // 2xx 范围内的状态码都会触发该函数。
    // 对响应数据做点什么
    // dataAxios 是 axios 返回数据中的 data
    const dataAxios = response.data;
    // 这个状态码是和后端约定的
    const code = dataAxios.code;
    // 正常响应处理
    return response;
  },
  async (error) => {
    // 超出 2xx 范围的状态码都会触发该函数。
    if (
      error &&error.response &&
      error.response.status === 403 &&
      !error.config.url.includes("refresh")
    ) {
      // 如果不是刷新token的请求，则尝试刷新token
      if (!isRefreshing) {
        isRefreshing = true;

        // 清空session中的token
        tool.session.remove("token");
        // 调用刷新token的接口
        return http
          .get("api/auth/v1.0/token/refresh")
          .then((res) => {
            if (res.code === "01") {
              // 更新本地存储的token
              tool.session.set("token", res.data);
              // 重新设置header
              error.config.headers["AUTH-TOKEN"] = res.data;
              // 执行队列中的请求
              retryQueue.forEach((cb) => cb(res.data));
              retryQueue = [];
              // 重试当前请求
              return axios(error.config);
            } else {
              // 刷新token失败，跳转到登录页
              router.replace({ path: "/" });
              ElMessage.error(res.message);
              return Promise.reject(res);
            }
          })
          .catch((err) => {
            // 刷新token失败，跳转到登录页
            router.replace({ path: "/" });
            return Promise.reject(err);
          })
          .finally(() => {
            isRefreshing = false;
          });
      } else {
        // 将请求加入队列
        return new Promise((resolve) => {
          retryQueue.push((token) => {
            error.config.headers["AUTH-TOKEN"] = token;
            resolve(axios(error.config));
          });
        });
      }
    }
    // console.log(error);
    return Promise.reject(error);
  }
);

const http = {
  /** put 请求
   * @param {string} url 接口地址
   * @param {object} data 请求参数
   * @param {object} settings 配置参数
   */
  put(url, data = {}, settings = {}) {
    return new Promise((resolve, reject) => {
      axios({
        method: "put",
        url: url,
        data: data,
        ...settings,
      })
        .then((response) => {
          resolve(response.data);
        })
        .catch((error) => {
          reject(error);
        });
    });
  },

  /** delete 请求
   * @param {string} url 接口地址
   * @param {object} data 请求参数
   * @param {object} settings 配置参数
   */
  delete(url, data = {}, settings = {}) {
    return new Promise((resolve, reject) => {
      axios({
        method: "delete",
        url: url,
        data: data,
        ...settings,
      })
        .then((response) => {
          resolve(response.data);
        })
        .catch((error) => {
          reject(error);
        });
    });
  },
  /** get 请求
   * @param {string} url 接口地址
   * @param {object} params 请求参数
   * @param {object} settings 配置参数
   */
  get(url, params = {}, settings = {}) {
    return new Promise((resolve, reject) => {
      axios({
        method: "get",
        url: url,
        params: params,
        ...settings,
      })
        .then((response) => {
          resolve(response.data);
        })
        .catch((error) => {
          reject(error);
        });
    });
  },

  /** post 请求
   * @param {string} url 接口地址
   * @param {object} params 请求参数
   * @param {object} settings 配置参数
   */
  post(url, data = {}, settings = {}) {
    return new Promise((resolve, reject) => {
      axios({
        method: "post",
        url: url,
        data: data,
        ...settings,
      })
        .then((response) => {
          resolve(response.data);
        })
        .catch((error) => {
          reject(error);
        });
    });
  },

  /** down 请求
   * @param  {string} url 接口地址
   * @param  {object} data 请求参数
   * @param  {object} settings 配置参数
   */
  down(url, data = {}, settings = {}) {
    return new Promise((resolve, reject) => {
      axios({
        url: url,
        data: data,
        responseType: "blob",
        ...settings,
      })
        .then((response) => {
          resolve(response.data);
        })
        .catch((error) => {
          reject(error);
        });
    });
  },
};

export default http;
